Popular Searches
Popular Course Categories
Popular Courses

Creating Page Classes

Creating Page Classes

Page Object Model

Creating Page Classes in Selenium WebDriver

Creating Page Classes is an important part of implementing the Page Object Model (POM) in Selenium automation. A Page Class represents a particular web page or a meaningful page component of an application and contains the locators and reusable methods required to interact with that page.

Instead of writing Selenium locators and browser interactions directly inside every test class, we create dedicated Page Classes. This keeps test cases clean, reduces code duplication, and makes the automation framework easier to maintain when the application's UI changes. Selenium's official documentation describes Page Objects as a way to model application pages as objects and keep page-specific implementation details in one place. :contentReference[oaicite:0]{index=0}

Course Resource: Selenium Training | Register for Course Demo


1. What is a Page Class?

A Page Class is a Java class created to represent a specific web page or page component of an application. It contains the locators of elements available on that page and methods that perform user actions on those elements.

For example, if an application contains a Login Page, Home Page, Product Page, Cart Page, and Checkout Page, separate Page Classes can be created for each major page.

LoginPage.java

HomePage.java

ProductsPage.java

CartPage.java

CheckoutPage.java

The test class then calls methods from these Page Classes instead of directly interacting with Selenium WebDriver elements.


2. Why Create Page Classes?

Creating Page Classes provides a clear separation between test logic and application UI interaction logic.

  • Reduces duplicate Selenium code.
  • Centralizes page locators.
  • Improves test readability.
  • Makes maintenance easier.
  • Improves code reusability.
  • Separates test logic from UI implementation.
  • Makes UI changes easier to manage.
  • Supports scalable automation frameworks.
  • Works effectively with TestNG, JUnit, and other testing frameworks.
  • Works well with Data Providers and external test data.

Selenium specifically highlights separation between test code and page-specific code as a major advantage of Page Objects. :contentReference[oaicite:1]{index=1}


3. Page Class Architecture

A typical Selenium framework separates test classes, Page Classes, utilities, and WebDriver management.

Test Class

    |

    v

Page Class

    |

    +-- Locators

    |

    +-- Page Methods

    |

    v

WebDriver

    |

    v

Web Application

The test class describes what should be tested, while the Page Class describes how the application page should be interacted with.


4. Basic Page Class Structure

A simple Page Class generally contains four important parts:

  1. WebDriver reference.
  2. Element locators.
  3. Constructor.
  4. Reusable page methods.

import org.openqa.selenium.By;

import org.openqa.selenium.WebDriver;

 

public class LoginPage {

 

    WebDriver driver;

 

    By username = By.id("username");

    By password = By.id("password");

    By loginButton = By.id("loginButton");

 

    public LoginPage(WebDriver driver) {

        this.driver = driver;

    }

 

    public void login(String user, String pass) {

        driver.findElement(username).sendKeys(user);

        driver.findElement(password).sendKeys(pass);

        driver.findElement(loginButton).click();

    }

}


5. WebDriver in a Page Class

The Page Class needs access to the WebDriver instance because Selenium uses WebDriver to locate and interact with browser elements.

private WebDriver driver;

 

public LoginPage(WebDriver driver) {

    this.driver = driver;

}

The driver is normally created by a test base class, driver factory, or setup method and then passed to the Page Class constructor.


6. Page Class Constructor

The constructor is used to initialize the Page Class with the WebDriver instance.

public LoginPage(WebDriver driver) {

    this.driver = driver;

}

This allows all methods inside the Page Class to use the same browser session.

A constructor can also perform a lightweight page-load check when the Page Object is created. Selenium's documentation shows this pattern as a way to verify that the expected page has been loaded, while keeping ordinary test assertions in the test class. :contentReference[oaicite:2]{index=2}


7. Creating Locators in a Page Class

Locators identify elements on the web page. They should normally be declared inside the Page Class rather than repeatedly written inside test methods.

private By username = By.id("username");

private By password = By.id("password");

private By loginButton = By.id("loginButton");

Common Selenium locator strategies include:

LocatorExampleTypical Use
idBy.id("username")Unique element ID
nameBy.name("email")Name attribute
classNameBy.className("login-btn")CSS class
tagNameBy.tagName("button")HTML tag
linkTextBy.linkText("Login")Exact link text
cssSelectorBy.cssSelector("#username")CSS selector
xpathBy.xpath("//input[@id='username']")Complex element identification


8. Using Private Locators

Locators should generally be hidden inside the Page Class using access modifiers such as private. Tests should interact with the page through meaningful methods rather than directly accessing locator variables.

private By usernameField = By.id("username");

private By passwordField = By.id("password");

private By loginButton = By.id("loginButton");

This improves encapsulation because the test does not need to know how a page element is located.


9. Creating Page Methods

Page methods represent actions or services that a user can perform on a page.

public void enterUsername(String username) {

    driver.findElement(usernameField).sendKeys(username);

}

 

public void enterPassword(String password) {

    driver.findElement(passwordField).sendKeys(password);

}

 

public void clickLogin() {

    driver.findElement(loginButton).click();

}

These methods allow the test class to interact with the page without knowing the underlying locators.


10. Creating a Complete LoginPage Class

import org.openqa.selenium.By;

import org.openqa.selenium.WebDriver;

 

public class LoginPage {

 

    private WebDriver driver;

 

    private By usernameField = By.id("username");

    private By passwordField = By.id("password");

    private By loginButton = By.id("loginButton");

 

    public LoginPage(WebDriver driver) {

        this.driver = driver;

    }

 

    public void enterUsername(String username) {

        driver.findElement(usernameField).sendKeys(username);

    }

 

    public void enterPassword(String password) {

        driver.findElement(passwordField).sendKeys(password);

    }

 

    public void clickLogin() {

        driver.findElement(loginButton).click();

    }

 

    public void login(String username, String password) {

        enterUsername(username);

        enterPassword(password);

        clickLogin();

    }

}


11. Using the Page Class in a Test

Once the Page Class is created, the test class can create an object of the Page Class and call its methods.

import org.testng.annotations.Test;

 

public class LoginTest {

 

    @Test

    public void validLoginTest() {

 

        LoginPage loginPage = new LoginPage(driver);

 

        loginPage.login("admin", "admin123");

    }

}

The test is now easier to read because it describes the user action instead of exposing every Selenium interaction.


12. Before Page Class Design

Without Page Classes, test code can become tightly coupled with the application's HTML structure.

@Test

public void loginTest() {

 

    driver.findElement(By.id("username"))

          .sendKeys("admin");

 

    driver.findElement(By.id("password"))

          .sendKeys("admin123");

 

    driver.findElement(By.id("loginButton"))

          .click();

}

If the username locator changes, every test containing that locator may need to be updated.


13. After Creating a Page Class

With a Page Class, the locator and interaction logic are centralized.

@Test

public void loginTest() {

 

    LoginPage loginPage = new LoginPage(driver);

 

    loginPage.login("admin", "admin123");

}

If the username locator changes, the change can normally be made inside LoginPage rather than throughout multiple tests. This centralized maintenance is one of the primary reasons Selenium recommends Page Objects. :contentReference[oaicite:3]{index=3}


14. Creating a HomePage Class

After successful login, the application may navigate to a Home Page. A separate Page Class can represent that page.

import org.openqa.selenium.By;

import org.openqa.selenium.WebDriver;

 

public class HomePage {

 

    private WebDriver driver;

 

    private By welcomeMessage = By.id("welcomeMessage");

    private By logoutButton = By.id("logout");

 

    public HomePage(WebDriver driver) {

        this.driver = driver;

    }

 

    public String getWelcomeMessage() {

        return driver.findElement(welcomeMessage).getText();

    }

 

    public void logout() {

        driver.findElement(logoutButton).click();

    }

}


15. Returning Another Page Class

When an action causes navigation to another page, the Page Class method can return the Page Class representing the destination.

public HomePage login(String username, String password) {

 

    driver.findElement(usernameField).sendKeys(username);

    driver.findElement(passwordField).sendKeys(password);

    driver.findElement(loginButton).click();

 

    return new HomePage(driver);

}

The test can then follow the application's user journey.

LoginPage loginPage = new LoginPage(driver);

HomePage homePage = loginPage.login("admin", "admin123");

 

System.out.println(homePage.getWelcomeMessage());

This approach models the application flow through Page Objects and can make page transitions explicit in the test code. :contentReference[oaicite:4]{index=4}


16. Creating a ProductsPage Class

A Products Page may contain product names, prices, add-to-cart buttons, filters, and sorting controls.

import org.openqa.selenium.By;

import org.openqa.selenium.WebDriver;

 

public class ProductsPage {

 

    private WebDriver driver;

 

    private By searchBox = By.id("search");

    private By searchButton = By.id("searchButton");

    private By firstProduct = By.cssSelector(".product-item");

 

    public ProductsPage(WebDriver driver) {

        this.driver = driver;

    }

 

    public void searchProduct(String productName) {

        driver.findElement(searchBox).clear();

        driver.findElement(searchBox).sendKeys(productName);

        driver.findElement(searchButton).click();

    }

 

    public void clickFirstProduct() {

        driver.findElement(firstProduct).click();

    }

}


17. Creating a CartPage Class

import org.openqa.selenium.By;

import org.openqa.selenium.WebDriver;

 

public class CartPage {

 

    private WebDriver driver;

 

    private By cartItems = By.cssSelector(".cart-item");

    private By checkoutButton = By.id("checkout");

 

    public CartPage(WebDriver driver) {

        this.driver = driver;

    }

 

    public int getCartItemCount() {

        return driver.findElements(cartItems).size();

    }

 

    public CheckoutPage clickCheckout() {

        driver.findElement(checkoutButton).click();

        return new CheckoutPage(driver);

    }

}


18. Creating a CheckoutPage Class

import org.openqa.selenium.By;

import org.openqa.selenium.WebDriver;

 

public class CheckoutPage {

 

    private WebDriver driver;

 

    private By firstName = By.id("firstName");

    private By lastName = By.id("lastName");

    private By address = By.id("address");

    private By placeOrder = By.id("placeOrder");

 

    public CheckoutPage(WebDriver driver) {

        this.driver = driver;

    }

 

    public void enterCustomerDetails(

            String firstNameValue,

            String lastNameValue,

            String addressValue) {

 

        driver.findElement(firstName).sendKeys(firstNameValue);

        driver.findElement(lastName).sendKeys(lastNameValue);

        driver.findElement(address).sendKeys(addressValue);

    }

 

    public void placeOrder() {

        driver.findElement(placeOrder).click();

    }

}


19. Page Class Naming Convention

Page Class names should clearly represent the page or component they model.

Application PageRecommended Class
Login PageLoginPage
Home PageHomePage
Product PageProductPage
Products PageProductsPage
Shopping CartCartPage
Checkout PageCheckoutPage
User ProfileProfilePage
Admin DashboardAdminDashboardPage


20. Page Class Naming Best Practice

Use clear and consistent names. Avoid generic names such as Page1, TestPage, or WebPage.

Good:

LoginPage

ProductsPage

CheckoutPage

 

Avoid:

Page1

TestPage

MyPage

WebPage2


21. Page Methods Should Represent User Actions

Page methods should ideally represent meaningful application actions rather than exposing low-level Selenium operations.

For example, instead of writing:

loginPage.clickButton();

loginPage.enterText();

loginPage.enterPassword();

a higher-level method can represent the complete user action:

loginPage.login("admin", "admin123");

This makes test cases easier to understand and keeps page-specific implementation inside the Page Class.


22. Avoid Exposing Page Internals

The Page Class should hide implementation details such as locators whenever possible.

Instead of:

loginPage.usernameField.sendKeys("admin");

prefer:

loginPage.enterUsername("admin");

This keeps the test independent from the actual HTML structure.


23. Page Classes and Encapsulation

Encapsulation means keeping the internal implementation of an object hidden and exposing only the operations that other classes need.

public class LoginPage {

 

    private By username = By.id("username");

 

    public void enterUsername(String value) {

        driver.findElement(username).sendKeys(value);

    }

}

The test does not need to know that the username field uses an ID locator.


24. Page Classes with Explicit Waits

Dynamic applications may require explicit waits before interacting with elements. Wait logic can be encapsulated within Page Class methods when it is specific to page behavior.

import java.time.Duration;

import org.openqa.selenium.support.ui.WebDriverWait;

 

public void clickLogin() {

 

    WebDriverWait wait =

        new WebDriverWait(driver, Duration.ofSeconds(10));

 

    wait.until(

        d -> d.findElement(loginButton).isEnabled()

    );

 

    driver.findElement(loginButton).click();

}

This keeps synchronization logic close to the page interaction that requires it.


25. Creating a BasePage Class

Large frameworks may contain common functionality shared by multiple Page Classes. A BasePage can be used to centralize reusable functionality.

import org.openqa.selenium.WebDriver;

 

public class BasePage {

 

    protected WebDriver driver;

 

    public BasePage(WebDriver driver) {

        this.driver = driver;

    }

 

    public String getPageTitle() {

        return driver.getTitle();

    }

 

    public String getCurrentUrl() {

        return driver.getCurrentUrl();

    }

}


26. Extending BasePage

Page Classes can extend BasePage to reuse common functionality.

public class LoginPage extends BasePage {

 

    private By username = By.id("username");

    private By password = By.id("password");

    private By loginButton = By.id("loginButton");

 

    public LoginPage(WebDriver driver) {

        super(driver);

    }

 

    public void login(String user, String pass) {

        driver.findElement(username).sendKeys(user);

        driver.findElement(password).sendKeys(pass);

        driver.findElement(loginButton).click();

    }

}


27. Creating a BasePage with Common Actions

import org.openqa.selenium.By;

import org.openqa.selenium.WebDriver;

 

public class BasePage {

 

    protected WebDriver driver;

 

    public BasePage(WebDriver driver) {

        this.driver = driver;

    }

 

    protected void click(By locator) {

        driver.findElement(locator).click();

    }

 

    protected void type(By locator, String text) {

        driver.findElement(locator).clear();

        driver.findElement(locator).sendKeys(text);

    }

 

    protected String getText(By locator) {

        return driver.findElement(locator).getText();

    }

 

    protected boolean isDisplayed(By locator) {

        return driver.findElement(locator).isDisplayed();

    }

}

Common methods should be kept focused. Avoid turning BasePage into a large collection of unrelated business logic.


28. LoginPage Using BasePage

public class LoginPage extends BasePage {

 

    private By username = By.id("username");

    private By password = By.id("password");

    private By loginButton = By.id("loginButton");

 

    public LoginPage(WebDriver driver) {

        super(driver);

    }

 

    public void enterUsername(String value) {

        type(username, value);

    }

 

    public void enterPassword(String value) {

        type(password, value);

    }

 

    public HomePage login(String user, String pass) {

        type(username, user);

        type(password, pass);

        click(loginButton);

 

        return new HomePage(driver);

    }

}


29. Creating Page Classes with PageFactory

Selenium provides PageFactory, which can be used to initialize Page Object fields and supports annotations such as @FindBy. The Selenium Java API documents PageFactory as a factory that simplifies working with Page Objects and initializes WebElement fields using a SearchContext. :contentReference[oaicite:5]{index=5}

import org.openqa.selenium.WebDriver;

import org.openqa.selenium.WebElement;

import org.openqa.selenium.support.FindBy;

import org.openqa.selenium.support.PageFactory;

 

public class LoginPage {

 

    private WebDriver driver;

 

    @FindBy(id = "username")

    private WebElement username;

 

    @FindBy(id = "password")

    private WebElement password;

 

    @FindBy(id = "loginButton")

    private WebElement loginButton;

 

    public LoginPage(WebDriver driver) {

        this.driver = driver;

        PageFactory.initElements(driver, this);

    }

 

    public void login(String user, String pass) {

        username.sendKeys(user);

        password.sendKeys(pass);

        loginButton.click();

    }

}


30. @FindBy Annotation

The @FindBy annotation allows an element to be described using Selenium locator strategies.

@FindBy(id = "username")

private WebElement username;

Other examples include:

@FindBy(name = "email")

private WebElement email;

 

@FindBy(css = ".login-button")

private WebElement loginButton;

 

@FindBy(xpath = "//button[@type='submit']")

private WebElement submitButton;

Selenium's PageFactory API supports locator annotations including FindBy-related mechanisms. :contentReference[oaicite:6]{index=6}


31. By Locators vs @FindBy

By Locators@FindBy
Uses By objectsUses WebElement fields
Explicit findElement callsElement fields are initialized through PageFactory
Simple and directConvenient for annotation-based Page Objects
Works without PageFactoryCommonly used with PageFactory


32. Creating Page Classes Without PageFactory

PageFactory is not required to implement the Page Object Model. Page Classes can simply store By locators and use WebDriver methods.

public class LoginPage {

 

    private WebDriver driver;

 

    private By username = By.id("username");

 

    public LoginPage(WebDriver driver) {

        this.driver = driver;

    }

 

    public void enterUsername(String value) {

        driver.findElement(username).sendKeys(value);

    }

}

This approach is straightforward and keeps the locator definition explicit.


33. Page Classes and TestNG

Page Classes can be used directly with TestNG test methods.

import org.testng.Assert;

import org.testng.annotations.Test;

 

public class LoginTest {

 

    @Test

    public void validLoginTest() {

 

        LoginPage loginPage = new LoginPage(driver);

 

        HomePage homePage =

            loginPage.login("admin", "admin123");

 

        Assert.assertTrue(

            homePage.getWelcomeMessage().contains("Welcome")

        );

    }

}

The test contains the validation, while the Page Classes contain page interaction logic. Selenium's guidance recommends keeping test assertions in tests rather than placing normal assertions inside Page Objects. :contentReference[oaicite:7]{index=7}


34. Page Classes and Data Providers

Data Providers can supply multiple test-data combinations while Page Classes handle the application interactions.

@DataProvider(name = "loginData")

public Object[][] loginData() {

    return new Object[][] {

        {"admin", "admin123"},

        {"manager", "manager123"},

        {"employee", "employee123"}

    };

}

 

@Test(dataProvider = "loginData")

public void loginTest(String username, String password) {

 

    LoginPage loginPage = new LoginPage(driver);

 

    loginPage.login(username, password);

}

This creates a clean separation:

DataProvider

     |

     v

Test Data

     |

     v

Test Method

     |

     v

Page Class

     |

     v

Selenium WebDriver


35. Page Classes and Assertions

Page Classes should generally provide information that the test can verify instead of performing the test's assertions themselves.

For example:

public String getWelcomeMessage() {

    return driver.findElement(welcomeMessage).getText();

}

The test performs the assertion:

String message = homePage.getWelcomeMessage();

 

Assert.assertTrue(

    message.contains("Welcome")

);

This maintains a clean separation between page behavior and test verification. Selenium's official guidance explicitly recommends that ordinary assertions belong in test code rather than Page Objects. :contentReference[oaicite:8]{index=8}


36. Page Classes and Navigation

A Page Class can return another Page Class when an action navigates to a different page.

public ProductsPage clickProducts() {

 

    driver.findElement(productsMenu).click();

 

    return new ProductsPage(driver);

}

The test can then continue the workflow:

HomePage homePage = new HomePage(driver);

 

ProductsPage productsPage =

    homePage.clickProducts();

 

productsPage.searchProduct("Laptop");


37. Modeling Successful and Failed Actions

The same action may have different expected outcomes. For example, a valid login may navigate to HomePage while an invalid login may remain on LoginPage and display an error.

public HomePage loginSuccessfully(

        String username,

        String password) {

 

    enterUsername(username);

    enterPassword(password);

    clickLogin();

 

    return new HomePage(driver);

}

 

public LoginPage loginExpectingFailure(

        String username,

        String password) {

 

    enterUsername(username);

    enterPassword(password);

    clickLogin();

 

    return new LoginPage(driver);

}

This makes the expected application flow explicit in the Page Class API. Selenium's Page Object guidance describes this pattern for actions that can result in different pages or states. :contentReference[oaicite:9]{index=9}


38. Page Class for Search

public class SearchPage {

 

    private WebDriver driver;

 

    private By searchBox = By.id("searchBox");

    private By searchButton = By.id("searchButton");

    private By results = By.cssSelector(".search-result");

 

    public SearchPage(WebDriver driver) {

        this.driver = driver;

    }

 

    public void search(String keyword) {

        driver.findElement(searchBox).clear();

        driver.findElement(searchBox).sendKeys(keyword);

        driver.findElement(searchButton).click();

    }

 

    public int getResultCount() {

        return driver.findElements(results).size();

    }

}


39. Page Class for Registration

public class RegistrationPage {

 

    private WebDriver driver;

 

    private By firstName = By.id("firstName");

    private By lastName = By.id("lastName");

    private By email = By.id("email");

    private By password = By.id("password");

    private By registerButton = By.id("register");

 

    public RegistrationPage(WebDriver driver) {

        this.driver = driver;

    }

 

    public void register(

            String first,

            String last,

            String emailValue,

            String passwordValue) {

 

        driver.findElement(firstName).sendKeys(first);

        driver.findElement(lastName).sendKeys(last);

        driver.findElement(email).sendKeys(emailValue);

        driver.findElement(password).sendKeys(passwordValue);

        driver.findElement(registerButton).click();

    }

}


40. Page Class for User Profile

public class ProfilePage {

 

    private WebDriver driver;

 

    private By profileName = By.id("profileName");

    private By email = By.id("email");

    private By saveButton = By.id("save");

 

    public ProfilePage(WebDriver driver) {

        this.driver = driver;

    }

 

    public void updateName(String name) {

        driver.findElement(profileName).clear();

        driver.findElement(profileName).sendKeys(name);

    }

 

    public void updateEmail(String value) {

        driver.findElement(email).clear();

        driver.findElement(email).sendKeys(value);

    }

 

    public void saveChanges() {

        driver.findElement(saveButton).click();

    }

}


41. Page Classes and Reusable Components

A complex page may contain reusable components such as navigation bars, product cards, menus, filters, headers, and footers. These can be represented using component objects instead of placing all functionality into one large Page Class.

HomePage

    |

    +-- Header

    |

    +-- NavigationMenu

    |

    +-- ProductSection

    |

    +-- Footer

Selenium documentation also describes Page Component Objects for representing discrete parts of a page and composing them inside Page Objects. :contentReference[oaicite:10]{index=10}


42. Page Component Example

public class ProductComponent {

 

    private WebElement root;

 

    public ProductComponent(WebElement root) {

        this.root = root;

    }

 

    public String getProductName() {

        return root.findElement(

            By.cssSelector(".product-name")

        ).getText();

    }

 

    public void addToCart() {

        root.findElement(

            By.cssSelector(".add-to-cart")

        ).click();

    }

}

A ProductsPage can then work with multiple ProductComponent objects.


43. Page Class with Product Components

public List<ProductComponent> getProducts() {

 

    List<WebElement> elements =

        driver.findElements(

            By.cssSelector(".product")

        );

 

    return elements.stream()

        .map(ProductComponent::new)

        .toList();

}

This composition approach can make complex pages easier to model and maintain. :contentReference[oaicite:11]{index=11}


44. Creating a Complete E-Commerce Page Flow

LoginPage

    |

    v

HomePage

    |

    v

ProductsPage

    |

    v

ProductDetailsPage

    |

    v

CartPage

    |

    v

CheckoutPage

    |

    v

OrderConfirmationPage

Each Page Class represents a meaningful stage of the user's journey through the application.


45. Complete E-Commerce Test Example

@Test

public void purchaseProductTest() {

 

    LoginPage loginPage =

        new LoginPage(driver);

 

    HomePage homePage =

        loginPage.login("admin", "admin123");

 

    ProductsPage productsPage =

        homePage.clickProducts();

 

    productsPage.searchProduct("Laptop");

 

    ProductDetailsPage productPage =

        productsPage.clickFirstProduct();

 

    productPage.addToCart();

 

    CartPage cartPage =

        productPage.openCart();

 

    CheckoutPage checkoutPage =

        cartPage.clickCheckout();

 

    checkoutPage.enterCustomerDetails(

        "John",

        "Smith",

        "Mumbai"

    );

 

    checkoutPage.placeOrder();

}

The test reads almost like a user journey because the Page Classes hide low-level Selenium implementation details.


46. Page Class and Wait Strategy

Dynamic web applications often require synchronization. Page Classes can encapsulate page-specific wait behavior.

public void waitForLoginButton() {

 

    WebDriverWait wait =

        new WebDriverWait(

            driver,

            Duration.ofSeconds(10)

        );

 

    wait.until(

        ExpectedConditions.elementToBeClickable(

            loginButton

        )

    );

}

Waits should be used deliberately rather than adding unnecessary fixed delays such as Thread.sleep().


47. Avoiding Thread.sleep()

Hard-coded sleeps can make automation slower and less reliable because they wait for a fixed amount of time regardless of whether the page is ready.

Instead of:

Thread.sleep(5000);

driver.findElement(loginButton).click();

prefer an explicit wait:

WebDriverWait wait =

    new WebDriverWait(driver, Duration.ofSeconds(10));

 

wait.until(

    ExpectedConditions.elementToBeClickable(loginButton)

).click();


48. Page Class Validation

A Page Class may perform a lightweight check to ensure that the correct page has been loaded.

public LoginPage(WebDriver driver) {

 

    this.driver = driver;

 

    if (!driver.getTitle().contains("Login")) {

        throw new IllegalStateException(

            "Expected Login Page but current page is: "

            + driver.getCurrentUrl()

        );

    }

}

This type of page-load verification is different from ordinary test assertions. Selenium's documentation specifically notes that checking whether the expected page has loaded can be appropriate when creating a Page Object. :contentReference[oaicite:12]{index=12}


49. Page Classes Should Not Contain Test Assertions

A common design mistake is putting assertions directly into every Page Class method.

Avoid:

public void verifyLogin() {

 

    Assert.assertEquals(

        driver.getTitle(),

        "Dashboard"

    );

}

Prefer returning information:

public String getPageTitle() {

    return driver.getTitle();

}

Then verify it in the test:

Assert.assertEquals(

    homePage.getPageTitle(),

    "Dashboard"

);


50. Page Classes and Encapsulated Business Actions

Page methods can represent meaningful business-level operations.

public void completeLogin(

        String username,

        String password) {

 

    enterUsername(username);

    enterPassword(password);

    clickLogin();

}

Instead of exposing every technical step to the test, the Page Class provides a reusable service.


51. Page Class Method Return Types

Page methods can return different types depending on the operation.

Return TypeTypical Purpose
voidAction with no useful return value
StringReturn text, title, or value
booleanReturn a condition or state
intReturn count or numeric value
Page ClassNavigate to another page
Component ClassReturn a page component


52. Fluent Page Class Methods

A Page Class can use a fluent style where methods return the current Page Object or another Page Object.

public LoginPage enterUsername(String username) {

 

    driver.findElement(usernameField)

          .sendKeys(username);

 

    return this;

}

 

public LoginPage enterPassword(String password) {

 

    driver.findElement(passwordField)

          .sendKeys(password);

 

    return this;

}

The test can then write:

loginPage

    .enterUsername("admin")

    .enterPassword("admin123")

    .clickLogin();

Selenium documents fluent APIs as one possible design approach for Page Objects. :contentReference[oaicite:13]{index=13}


53. Page Class Package Structure

A common project structure separates Page Classes from tests and utilities.

src

|-- test

    |-- java

        |-- tests

        |   |-- LoginTest.java

        |   |-- ProductTest.java

        |   |-- CheckoutTest.java

        |

        |-- pages

        |   |-- LoginPage.java

        |   |-- HomePage.java

        |   |-- ProductsPage.java

        |   |-- ProductDetailsPage.java

        |   |-- CartPage.java

        |   |-- CheckoutPage.java

        |

        |-- components

        |   |-- ProductComponent.java

        |   |-- HeaderComponent.java

        |

        |-- utilities

            |-- DriverFactory.java

            |-- ConfigReader.java

            |-- ExcelReader.java


54. Page Classes with DriverFactory

In a scalable framework, WebDriver creation can be separated from Page Classes.

public class DriverFactory {

 

    private static WebDriver driver;

 

    public static WebDriver createDriver() {

        driver = new ChromeDriver();

        return driver;

    }

 

    public static WebDriver getDriver() {

        return driver;

    }

}

Page Classes receive the driver instead of creating their own browser session.

WebDriver driver = DriverFactory.createDriver();

 

LoginPage loginPage =

    new LoginPage(driver);


55. Page Class Should Not Usually Create the Browser

A Page Class should normally represent a page rather than manage the complete lifecycle of the browser.

Avoid:

public LoginPage() {

    driver = new ChromeDriver();

}

Prefer:

public LoginPage(WebDriver driver) {

    this.driver = driver;

}

This allows the same Page Class to work with different browser configurations and framework-level WebDriver management.


56. Page Classes and Cross-Browser Testing

Because the Page Class receives a WebDriver instance, the same Page Class can generally work with Chrome, Firefox, Edge, or another supported WebDriver implementation.

WebDriver driver = new ChromeDriver();

LoginPage loginPage = new LoginPage(driver);

or:

WebDriver driver = new FirefoxDriver();

LoginPage loginPage = new LoginPage(driver);

The Page Class does not need to change simply because the browser implementation changes.


57. Page Classes with Parameterized Test Data

@DataProvider(name = "users")

public Object[][] users() {

    return new Object[][] {

        {"admin", "admin123"},

        {"manager", "manager123"},

        {"employee", "employee123"}

    };

}

 

@Test(dataProvider = "users")

public void loginTest(

        String username,

        String password) {

 

    LoginPage loginPage =

        new LoginPage(driver);

 

    loginPage.login(username, password);

}

This combination is useful for building reusable data-driven Selenium frameworks.


58. Page Class with Error Message

Negative test cases may need access to validation messages.

private By errorMessage =

    By.cssSelector(".login-error");

 

public String getErrorMessage() {

    return driver.findElement(errorMessage)

                 .getText();

}

The test can then verify the message:

loginPage.loginExpectingFailure(

    "invalid",

    "wrongPassword"

);

 

Assert.assertEquals(

    loginPage.getErrorMessage(),

    "Invalid username or password"

);


59. Page Class for Dropdowns

Page Classes can encapsulate interactions with dropdowns and other complex controls.

private By countryDropdown =

    By.id("country");

 

public void selectCountry(String country) {

 

    Select select =

        new Select(

            driver.findElement(countryDropdown)

        );

 

    select.selectByVisibleText(country);

}


60. Page Class for Checkboxes

private By termsCheckbox =

    By.id("terms");

 

public void acceptTerms() {

 

    WebElement checkbox =

        driver.findElement(termsCheckbox);

 

    if (!checkbox.isSelected()) {

        checkbox.click();

    }

}


61. Page Class for Radio Buttons

private By maleRadio =

    By.id("male");

 

private By femaleRadio =

    By.id("female");

 

public void selectGender(String gender) {

 

    if (gender.equalsIgnoreCase("male")) {

        driver.findElement(maleRadio).click();

    } else if (gender.equalsIgnoreCase("female")) {

        driver.findElement(femaleRadio).click();

    }

}


62. Page Class for Tables

Tables can also be represented through Page Class methods.

private By tableRows =

    By.cssSelector("table tbody tr");

 

public int getRowCount() {

    return driver.findElements(tableRows).size();

}

For a more complex table, the Page Class can provide methods to retrieve specific rows or values.


63. Page Classes for Reusable Navigation

Navigation components are often shared across multiple pages.

public class HeaderComponent {

 

    private WebDriver driver;

 

    private By homeLink = By.id("home");

    private By productsLink = By.id("products");

    private By profileLink = By.id("profile");

 

    public HeaderComponent(WebDriver driver) {

        this.driver = driver;

    }

 

    public HomePage clickHome() {

        driver.findElement(homeLink).click();

        return new HomePage(driver);

    }

 

    public ProductsPage clickProducts() {

        driver.findElement(productsLink).click();

        return new ProductsPage(driver);

    }

}


64. Complete Page Class Architecture

                    Test Classes

                         |

                         v

                 Page Object Classes

                         |

          +--------------+--------------+

          |              |              |

      Locators       Page Methods    Components

          |              |              |

          +--------------+--------------+

                         |

                         v

                    WebDriver

                         |

                         v

                  Web Application


65. Real-World Login Page Class

import org.openqa.selenium.By;

import org.openqa.selenium.WebDriver;

 

public class LoginPage {

 

    private final WebDriver driver;

 

    private final By username =

        By.id("username");

 

    private final By password =

        By.id("password");

 

    private final By loginButton =

        By.id("loginButton");

 

    private final By errorMessage =

        By.cssSelector(".login-error");

 

    public LoginPage(WebDriver driver) {

        this.driver = driver;

    }

 

    public LoginPage enterUsername(String value) {

        driver.findElement(username)

              .clear();

 

        driver.findElement(username)

              .sendKeys(value);

 

        return this;

    }

 

    public LoginPage enterPassword(String value) {

        driver.findElement(password)

              .clear();

 

        driver.findElement(password)

              .sendKeys(value);

 

        return this;

    }

 

    public HomePage clickLogin() {

        driver.findElement(loginButton)

              .click();

 

        return new HomePage(driver);

    }

 

    public HomePage login(

            String usernameValue,

            String passwordValue) {

 

        enterUsername(usernameValue);

        enterPassword(passwordValue);

 

        return clickLogin();

    }

 

    public String getErrorMessage() {

        return driver.findElement(errorMessage)

                     .getText();

    }

}


66. Complete Test Using the Page Class

import org.testng.Assert;

import org.testng.annotations.Test;

 

public class LoginTest {

 

    @Test

    public void validLoginTest() {

 

        LoginPage loginPage =

            new LoginPage(driver);

 

        HomePage homePage =

            loginPage.login(

                "admin",

                "admin123"

            );

 

        Assert.assertTrue(

            homePage.getWelcomeMessage()

                    .contains("Welcome")

        );

    }

}


67. Page Class Design: Good vs Poor

Good DesignPoor Design
Locators are centralizedLocators repeated across tests
Methods represent user actionsTests directly manipulate WebElements
Page-specific logic stays in Page ClassPage logic scattered across test classes
Tests focus on verificationTests contain excessive UI implementation details
Reusable methodsDuplicated Selenium code
Clear Page Class namesGeneric class names


68. Common Mistakes When Creating Page Classes

  • Creating one giant Page Class for the entire application.
  • Putting assertions everywhere inside Page Classes.
  • Making all locators public.
  • Duplicating the same locator in multiple classes.
  • Creating a new WebDriver inside every Page Class.
  • Using Thread.sleep() excessively.
  • Putting test-data generation inside page interaction methods.
  • Mixing test logic with page implementation.
  • Using unclear Page Class names.
  • Exposing raw WebElements unnecessarily.
  • Creating methods that perform unrelated operations.
  • Sharing unsafe WebDriver state across parallel tests.


69. Best Practices for Creating Page Classes

  • Use one Page Class for a meaningful page or reusable page component.
  • Keep locators inside the relevant Page Class.
  • Use private fields for implementation details.
  • Use meaningful method names.
  • Keep test assertions in test classes.
  • Pass WebDriver through the constructor.
  • Keep browser creation outside Page Classes.
  • Use explicit waits when synchronization is required.
  • Return another Page Object when an action navigates to another page.
  • Use reusable component objects for repeated UI sections.
  • Keep Page Classes focused on page services and behavior.
  • Avoid exposing the underlying WebDriver unnecessarily.
  • Use consistent package and naming conventions.
  • Keep Page Classes small enough to remain understandable.

These practices align with Selenium's Page Object guidance, which emphasizes exposing page services through methods, hiding implementation details, minimizing duplication, and avoiding ordinary assertions inside Page Objects. :contentReference[oaicite:14]{index=14}


70. Practical Project Structure

selenium-project

|

|-- src

|   |-- test

|       |-- java

|           |

|           |-- tests

|           |   |-- LoginTest.java

|           |   |-- SearchTest.java

|           |   |-- ProductTest.java

|           |   |-- CheckoutTest.java

|           |

|           |-- pages

|           |   |-- BasePage.java

|           |   |-- LoginPage.java

|           |   |-- HomePage.java

|           |   |-- SearchPage.java

|           |   |-- ProductsPage.java

|           |   |-- ProductDetailsPage.java

|           |   |-- CartPage.java

|           |   |-- CheckoutPage.java

|           |

|           |-- components

|           |   |-- HeaderComponent.java

|           |   |-- ProductComponent.java

|           |

|           |-- data

|           |   |-- LoginDataProvider.java

|           |   |-- ProductDataProvider.java

|           |

|           |-- utilities

|               |-- DriverFactory.java

|               |-- ConfigReader.java

|               |-- ExcelReader.java

|

|-- testng.xml

|-- pom.xml


71. Page Classes in a Selenium Automation Framework

                  TestNG

                    |

                    v

               Test Classes

                    |

                    v

              Page Classes

                    |

        +-----------+-----------+

        |           |           |

    LoginPage   ProductsPage  CartPage

        |           |           |

        +-----------+-----------+

                    |

                    v

               WebDriver

                    |

                    v

              Browser

                    |

                    v

             Web Application


72. Complete Practical Workflow

  1. Create the Selenium project.
  2. Configure WebDriver management.
  3. Create a pages package.
  4. Create a BasePage if common functionality is required.
  5. Create one Page Class for each important application page.
  6. Identify stable locators for page elements.
  7. Declare locators inside the corresponding Page Class.
  8. Create reusable methods for page actions.
  9. Return destination Page Objects when navigation occurs.
  10. Create test classes separately.
  11. Use TestNG Data Providers for multiple test-data combinations when needed.
  12. Perform assertions in test classes.
  13. Execute the tests.
  14. Generate test reports.


73. Page Class vs Test Class

Page ClassTest Class
Contains page locatorsContains test scenarios
Contains page interaction methodsContains assertions
Represents application UIRepresents validation requirements
Hides Selenium implementation detailsUses Page Class methods
Focuses on reusable behaviorFocuses on test verification


74. Interview Questions on Creating Page Classes

1. What is a Page Class?

A Page Class is a class that represents a web page or reusable page component and contains its locators and interaction methods.

2. Why are Page Classes used in Selenium?

They reduce duplication, improve maintainability, separate test logic from UI implementation, and provide reusable page-level operations.

3. What should a Page Class contain?

It commonly contains the WebDriver reference, locators, constructor, waits where appropriate, and reusable page interaction methods.

4. Should a Page Class contain assertions?

Ordinary test assertions should generally remain in the test class. A Page Object may perform a page-load check when it is instantiated. :contentReference[oaicite:15]{index=15}

5. Why is the WebDriver passed to the Page Class constructor?

It allows the Page Class to use the same browser session managed by the test framework.

6. Should a Page Class create a new WebDriver?

Normally no. WebDriver creation and lifecycle management are better handled by framework-level setup or a DriverFactory.

7. What is the advantage of private locators?

Private locators hide implementation details and encourage tests to use meaningful Page Class methods.

8. What is PageFactory?

PageFactory is a Selenium Java utility that can initialize Page Object fields and is commonly used with annotations such as @FindBy. :contentReference[oaicite:16]{index=16}

9. Can Page Classes return other Page Classes?

Yes. Returning another Page Class is useful when an action navigates to another page.

10. Can Page Classes be used with TestNG?

Yes. TestNG test methods can create Page Class objects and call their reusable methods.

11. Can Page Classes work with Data Providers?

Yes. Data Providers can supply test data while Page Classes handle browser interactions.

12. What is BasePage?

BasePage is a common parent class that can contain reusable functionality shared by multiple Page Classes.

13. What is a Page Component?

A Page Component represents a reusable section of a web page, such as a product card, header, navigation menu, or footer. :contentReference[oaicite:17]{index=17}

14. Why should test classes avoid direct locators?

Keeping locators in Page Classes reduces duplication and isolates tests from changes in the application's HTML structure.

15. What is the main goal of Page Classes?

The main goal is to create a maintainable abstraction between automated tests and the application's user interface.


75. Quick Reference Table

ConceptDescription
Page ClassRepresents a web page or page component
WebDriverBrowser automation interface used by Page Classes
LocatorIdentifies an element on the page
Page MethodRepresents an action or service offered by the page
BasePageContains common functionality for Page Classes
PageFactorySelenium utility for initializing Page Object fields
@FindByAnnotation used to define element lookup information
Page ComponentRepresents a reusable section of a page
DataProviderSupplies multiple test-data combinations
Test ClassContains scenarios and assertions


76. Learning Roadmap for Creating Page Classes

  1. Learn Java classes and objects.
  2. Understand Selenium WebDriver.
  3. Learn Selenium locator strategies.
  4. Understand the Page Object Model.
  5. Create a basic LoginPage.
  6. Add locators to the Page Class.
  7. Create reusable page methods.
  8. Pass WebDriver through constructors.
  9. Create multiple Page Classes.
  10. Return Page Objects after navigation.
  11. Create a BasePage for common functionality.
  12. Learn PageFactory and @FindBy.
  13. Create reusable Page Components.
  14. Integrate Page Classes with TestNG.
  15. Integrate Page Classes with Data Providers.
  16. Add explicit waits and synchronization.
  17. Build a complete POM-based Selenium framework.


77. Practical Exercises

  1. Create a LoginPage class with username, password, and login button locators.
  2. Create a HomePage class with welcome message and logout methods.
  3. Create a SearchPage class for product searches.
  4. Create a ProductsPage class with product-related actions.
  5. Create a CartPage class with cart item and checkout methods.
  6. Create a CheckoutPage class with customer information fields.
  7. Create a BasePage class with common click, type, and text methods.
  8. Create a HeaderComponent class for common navigation.
  9. Use PageFactory with @FindBy to create a LoginPage.
  10. Create a Data Provider containing multiple login credentials.
  11. Execute the same LoginPage workflow using different data sets.
  12. Build a complete e-commerce workflow using multiple Page Classes.


78. Real-World Example: Login Automation

Suppose an application contains a login page with username, password, and login button. Instead of putting all Selenium commands into every test, create a LoginPage.

public class LoginPage {

 

    private WebDriver driver;

 

    private By username =

        By.id("username");

 

    private By password =

        By.id("password");

 

    private By loginButton =

        By.id("loginButton");

 

    public LoginPage(WebDriver driver) {

        this.driver = driver;

    }

 

    public HomePage login(

            String user,

            String pass) {

 

        driver.findElement(username)

              .sendKeys(user);

 

        driver.findElement(password)

              .sendKeys(pass);

 

        driver.findElement(loginButton)

              .click();

 

        return new HomePage(driver);

    }

}

The test then becomes:

@Test

public void loginTest() {

 

    LoginPage loginPage =

        new LoginPage(driver);

 

    HomePage homePage =

        loginPage.login(

            "admin",

            "admin123"

        );

 

    Assert.assertTrue(

        homePage.getWelcomeMessage()

                .contains("Welcome")

    );

}


79. Real-World Page Object Architecture

                    Test Data

                        |

                        v

                 TestNG DataProvider

                        |

                        v

                   Test Class

                        |

                        v

                  LoginPage

                        |

                        v

                  HomePage

                        |

                        v

                ProductsPage

                        |

                        v

                  CartPage

                        |

                        v

                CheckoutPage

                        |

                        v

                    WebDriver

                        |

                        v

                   Browser

                        |

                        v

                 Application


80. Summary

Creating Page Classes is a fundamental practice when building a maintainable Selenium automation framework using the Page Object Model. A Page Class represents a web page or meaningful page component and contains its locators and reusable interaction methods.

The WebDriver instance is normally passed into the Page Class constructor, while locators remain encapsulated inside the class. Page methods should represent meaningful user actions such as login, search, checkout, navigation, or form submission.

Tests should generally focus on scenarios and assertions, while Page Classes handle the application's UI interaction details. When navigation occurs, Page methods can return another Page Object to model the application's workflow.

For larger frameworks, Page Classes can be combined with BasePage classes, PageFactory, @FindBy, Page Components, TestNG Data Providers, explicit waits, DriverFactory, Maven, CI/CD, and reporting tools.

Final Takeaway: A well-designed Page Class creates a clean boundary between Selenium implementation and test scenarios. When the application's UI changes, page-specific changes can usually be isolated to the relevant Page Class, reducing duplication and improving framework maintainability. :contentReference[oaicite:18]{index=18}


81. Course Resources

whatsapp